package com.zoe.onelink.business.util;


import com.zoe.onelink.common.enumeration.ExceptionCodeEnum;
import com.zoe.onelink.common.exception.ApiException;
import lombok.extern.slf4j.Slf4j;
import org.apache.cxf.helpers.IOUtils;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;

import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * <p>标题: </p>
 * <p>描述: </p>
 * <p>版权: Copyright (c) 2016</p>
 * <p>公司: 智业软件股份有限公司</p>
 *
 * @version: 1.0
 * @author: cxy
 * @date 2016/9/12
 */
@Slf4j
@Deprecated
public final class HttpClient {

    private final static String CONTENT_TYPE_TEXT_JSON = "text/json";

    /**
     * 连接超时时间，单位毫秒
     */
    private static final int CONNECT_TIMEOUT = 5000;
    /**
     * 从connect Manager(连接池)获取Connection 超时时间，单位毫秒
     */
    private static final int REQUEST_TIMEOUT = 1000;
    /**
     * 请求获取数据的超时时间(即响应时间)，单位毫秒
     */
    private static final int SOCKET_TIMEOUT = 30000;
    /**
     * 找不到请求地址
     */
    public static final int HTTP_STATUS_404_NOT_FOUND = 404;

    private HttpClient() {
    }

    /**
     * post请求
     *
     * @param url     url地址
     * @param headers 请求头
     * @param params  请求体
     * @return 响应内容
     * @throws IOException
     */
    public static String post(String url, Map<String, String> headers, Map<String, String> params) throws IOException {
        return post(url, headers, params, CONNECT_TIMEOUT, REQUEST_TIMEOUT, SOCKET_TIMEOUT);
    }

    /**
     * post请求
     *
     * @param url           url地址
     * @param headers       请求头
     * @param params        请求体
     * @param socketTimeout 请求获取数据的超时时间(即响应时间)，单位毫秒
     * @return 响应内容
     * @throws IOException
     */
    public static String post(String url, Map<String, String> headers, Map<String, String> params, int socketTimeout) throws IOException {
        return post(url, headers, params, CONNECT_TIMEOUT, REQUEST_TIMEOUT, socketTimeout);
    }

    /**
     * post请求
     *
     * @param url            url地址
     * @param headers        请求头
     * @param params         请求体
     * @param connectTimeout 连接超时时间，单位毫秒
     * @param requestTimeout 从connect Manager(连接池)获取Connection 超时时间，单位毫秒
     * @param socketTimeout  请求获取数据的超时时间(即响应时间)，单位毫秒
     * @return 响应内容
     * @throws IOException
     */
    public static String post(String url, Map<String, String> headers, Map<String, String> params, int connectTimeout, int requestTimeout, int socketTimeout) throws IOException {
        log.debug("create http post:" + url);
        CloseableHttpClient httpclient = HttpClients.createDefault();
        HttpPost httpPost = postForm(url, headers, params);
        //设置超时
        //setConnectTimeout：设置连接超时时间，单位毫秒。
        //setConnectionRequestTimeout：设置从connect Manager(连接池)获取Connection 超时时间，单位毫秒。这个属性是新加的属性，因为目前版本是可以共享连接池的。
        //setSocketTimeout：请求获取数据的超时时间(即响应时间)，单位毫秒。 如果访问一个接口，多少时间内无法返回数据，就直接放弃此次调用。
        RequestConfig requestConfig = RequestConfig.custom()
                .setConnectTimeout(connectTimeout).setConnectionRequestTimeout(requestTimeout)
                .setSocketTimeout(socketTimeout).build();
        httpPost.setConfig(requestConfig);

        return invoke(httpclient, httpPost);
    }

    public static String postJson(String url, Map<String, String> headers, String jsonParams) throws IOException {
        return postJson(url, headers, jsonParams, CONNECT_TIMEOUT, REQUEST_TIMEOUT, SOCKET_TIMEOUT);
    }

    /**
     * post请求（JSON）
     *
     * @param url            url地址
     * @param headers        请求头
     * @param jsonParams     请求体
     * @param connectTimeout 连接超时时间，单位毫秒
     * @param requestTimeout 从connect Manager(连接池)获取Connection 超时时间，单位毫秒
     * @param socketTimeout  请求获取数据的超时时间(即响应时间)，单位毫秒
     * @return 响应内容
     * @throws IOException
     */
    public static String postJson(String url, Map<String, String> headers, String jsonParams, int connectTimeout, int requestTimeout, int socketTimeout) throws IOException {
        log.debug("create http post:" + url);
        CloseableHttpClient httpclient = HttpClients.createDefault();

        HttpPost httpPost = packageJsonPost(url, headers, jsonParams);
        //设置超时
        //setConnectTimeout：设置连接超时时间，单位毫秒。
        //setConnectionRequestTimeout：设置从connect Manager(连接池)获取Connection 超时时间，单位毫秒。这个属性是新加的属性，因为目前版本是可以共享连接池的。
        //setSocketTimeout：请求获取数据的超时时间(即响应时间)，单位毫秒。 如果访问一个接口，多少时间内无法返回数据，就直接放弃此次调用。
        RequestConfig requestConfig = RequestConfig.custom()
                .setConnectTimeout(connectTimeout).setConnectionRequestTimeout(requestTimeout)
                .setSocketTimeout(socketTimeout).build();
        httpPost.setConfig(requestConfig);

        return invoke(httpclient, httpPost);
    }

    /**
     * post请求
     * 没有设置超时时间
     *
     * @param url     url地址
     * @param headers 请求头
     * @param params  请求体
     * @return 响应内容
     * @throws IOException
     */
    public static String postDefault(String url, Map<String, String> headers, Map<String, String> params) throws IOException {
        log.debug("create http post:" + url);
        CloseableHttpClient httpclient = HttpClients.createDefault();
        HttpPost httpPost = postForm(url, headers, params);
        return invoke(httpclient, httpPost);
    }


    /**
     * get请求
     *
     * @param url url地址
     * @return 响应内容
     * @throws IOException
     */
    public static String get(String url) throws IOException {
        return get(url, CONNECT_TIMEOUT, REQUEST_TIMEOUT, SOCKET_TIMEOUT);
    }

    /**
     * get请求
     *
     * @param url            url地址
     * @param connectTimeout 连接超时时间，单位毫秒
     * @param requestTimeout 从connect Manager(连接池)获取Connection 超时时间，单位毫秒
     * @param socketTimeout  请求获取数据的超时时间(即响应时间)，单位毫秒
     * @return 响应内容
     * @throws IOException
     */
    public static String get(String url, int connectTimeout, int requestTimeout, int socketTimeout) throws IOException {
        log.debug("create http get:" + url);
        CloseableHttpClient httpclient = HttpClients.createDefault();
        HttpGet httpGet = new HttpGet(url);
        RequestConfig requestConfig = RequestConfig.custom()
                .setConnectTimeout(connectTimeout).setConnectionRequestTimeout(requestTimeout)
                .setSocketTimeout(socketTimeout).build();
        httpGet.setConfig(requestConfig);
        return invoke(httpclient, httpGet);
    }

    /**
     * 调用接口
     *
     * @param httpclient     请求客户端
     * @param httpUriRequest uri请求对象
     * @return 响应字符串
     * @throws IOException
     */
    private static String invoke(CloseableHttpClient httpclient,
                                 HttpUriRequest httpUriRequest) throws IOException {
        // 外部调用开始 记录时间
        String result = null;
        try {
            //====请求开始日志start====
            String header = getHeader(httpUriRequest);
            String params = getParams(httpUriRequest);
            String requestUrl = httpUriRequest.getURI().toString();

            //====请求开始日志end====
            CloseableHttpResponse response = httpclient.execute(httpUriRequest);
            if (response == null) {
                return null;
                // 找不到请求地址
            } else if (response.getStatusLine() != null && response.getStatusLine().getStatusCode() == HTTP_STATUS_404_NOT_FOUND) {
                throw ApiException.createEx(ExceptionCodeEnum.HTTP_ERROR, "expMessage", requestUrl, header, params, ExceptionCodeEnum.HTTP_ERROR.getCode());
            }
            result = paseResponse(response);
            response.close();
        } catch (Exception e) {
            throw e;
        }
        return result;
    }

    /**
     * 解析响应对象
     *
     * @param response 响应对象
     * @return 响应字符串
     * @throws IOException
     */
    private static String paseResponse(CloseableHttpResponse response) throws IOException {
        HttpEntity entity = response.getEntity();
        return EntityUtils.toString(entity);
    }

    /**
     * 封装请求头，请求体
     *
     * @param url     url
     * @param headers 请求头map
     * @param params  请求体
     * @return HttpPost post请求对象
     */
    private static HttpPost postForm(String url, Map<String, String> headers, Map<String, String> params) {

        HttpPost httpPost = new HttpPost(url);
        List<NameValuePair> nvps = new ArrayList<>();

        if (params != null) {
            Set<String> keySet = params.keySet();
            for (String key : keySet) {
                nvps.add(new BasicNameValuePair(key, params.get(key)));
            }
        }

        try {
            log.debug("set utf-8 form entity to httppost");
            httpPost.setEntity(new UrlEncodedFormEntity(nvps, "UTF-8"));
            log.debug("set utf-8 form header to httppost");
            if (headers != null) {
                Set<String> keySet = headers.keySet();
                for (String key : keySet) {
                    httpPost.addHeader(key, headers.get(key));
                }
            }
        } catch (UnsupportedEncodingException e) {
            log.error("UnsupportedEncodingException", e);
        }

        return httpPost;
    }

    /**
     * 封装请求头，请求体
     *
     * @param url        url
     * @param headers    请求头map
     * @param jsonParams 请求体
     * @return HttpPost post请求对象
     */
    private static HttpPost packageJsonPost(String url, Map<String, String> headers, String jsonParams) {

        HttpPost httpPost = new HttpPost(url);

        log.debug("set utf-8 form entity to httppost");
        StringEntity stringEntity = new StringEntity(jsonParams, ContentType.APPLICATION_JSON);
        log.debug("set utf-8 form header to httppost");
        httpPost.setEntity(stringEntity);
        if (headers != null) {
            Set<String> keySet = headers.keySet();
            for (String key : keySet) {
                httpPost.addHeader(key, headers.get(key));
            }
        }

        return httpPost;
    }

    private static String getHeader(HttpUriRequest httpUriRequest) {
        StringBuilder sb = new StringBuilder();
        Header[] headers = httpUriRequest.getAllHeaders();
        for (Header header : headers) {
            sb.append(header.getName()).append("=").append(header.getValue()).append("&");
        }
        return sb.toString();
    }

    private static String getParams(HttpUriRequest httpUriRequest) {
        if (httpUriRequest instanceof HttpPost) {
            HttpEntity entity = ((HttpPost) httpUriRequest).getEntity();
            try {
                InputStream content = entity.getContent();
                return IOUtils.toString(content);
            } catch (Exception e) {
                log.error(e.getMessage(), e);
            }
        } else if (httpUriRequest instanceof HttpGet) {
            String[] urls = httpUriRequest.getURI().toString().split("\\?");
            if (urls.length == 2) {
                String url = null;
                try {
                    url = urls[1];
                    url = URLDecoder.decode(url, "UTF-8");
                    return url;
                } catch (Exception e) {
                    log.error(e.getMessage(), e);
                }
            }
        }
        return "";
    }

}
